package com.huibo.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huibo.algorithm.Store;
import com.huibo.algorithm.Stuff;
import com.huibo.algorithm.StuffOperator;
import com.huibo.common.ChangeEmployee;
import com.huibo.common.R;
import com.huibo.common.WeekData;
import com.huibo.common.WorkForm;
import com.huibo.entity.Company;
import com.huibo.entity.Employee;
import com.huibo.service.CompanyService;
import com.huibo.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/form")
public class FormController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private EmployeeService employeeService;

    @Autowired
    private CompanyService companyService;

    /**
     * 返回一周的表单
     * @param weekData
     * @return
     */
    @PostMapping
    public R<WorkForm> formBack(@RequestBody WeekData weekData){
        //首先在redis中查找有没有对应的一周的数据，有的话直接返回
        String index = weekData.getWeek().toString() + "_" + weekData.getCompany().getName();
        String data = redisTemplate.opsForValue().get(index);
        if(data != null){
            WorkForm form = JSON.parseObject(data,new TypeReference<WorkForm>(){});
            return R.success(form);
        }else{
            //redis中没有对应一周的数据，那么重新调用api方法，生成新的一周的数据，并且放入到redis中
            WorkForm workForm = dataPro(weekData.getCompany().getName(),weekData.getCompany().getId());
            String string = JSON.toJSONString(workForm);
            redisTemplate.opsForValue().set(index,string);
            return R.success(workForm);
        }
    }

    /**
     * 按职位查询表单
     * @param weekData
     * @return
     */
    @PostMapping("/pos")
    public R<WorkForm> formBackByPos(@RequestBody WeekData weekData){
        String index = weekData.getWeek().toString() + "_" + weekData.getCompany().getName();
        String data = redisTemplate.opsForValue().get(index);
        if(data == null){
            return R.error("先查看总排班表！");
        }
        WorkForm workForm = JSON.parseObject(data,new TypeReference<WorkForm>(){});

        //先准备员工信息集合,只需要准备员工id转为String的集合
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getPos,weekData.getPos()).eq(Employee::getMarketId,weekData.getCompany().getName());
        List<Employee> employeeList = employeeService.list(queryWrapper);
        Set<String> set = new HashSet<>();
        for(Employee e : employeeList){
            set.add(e.getName());
        }
        //拿到初始表单之后，在表单里面进行筛选，得到所需要的人员，并构建新的表单返回
        //初始化返回表单

        List<Map<String,List<Integer>>> out = new ArrayList<>();
        for(int i = 1;i<=7;i++){
            Map<String,List<Integer>> resDay = new HashMap<>();
            Map<String, List<Integer>> day = workForm.getDay(i);
            Set<Map.Entry<String, List<Integer>>> entries = day.entrySet();
            for(Map.Entry<String, List<Integer>> entry : entries){
                if(set.contains(entry.getKey())){
                    resDay.put(entry.getKey(),entry.getValue());
                }
            }
            out.add(resDay);
        }
        WorkForm resForm = new WorkForm(out.get(0),out.get(1),out.get(2),out.get(3),out.get(4),out.get(5),out.get(6));
        return R.success(resForm);
    }


    /**
     * 调换员工，更新表单
     * @param changeEmployee
     * @return
     */
    @PostMapping("/change")
    public R<String> change(@RequestBody ChangeEmployee changeEmployee){
        String index = changeEmployee.getWeekData().getWeek().toString() + "_" + changeEmployee.getWeekData().getCompany().getName();
        String data = redisTemplate.opsForValue().get(index);
        WorkForm form = JSON.parseObject(data,new TypeReference<WorkForm>(){});
        int day_x = changeEmployee.getDay1();
        int day_y = changeEmployee.getDay2();
        String employeeId1 = changeEmployee.getEmployee1().getName();
        String employeeId2 = changeEmployee.getEmployee2().getName();

        //检验两个员工在两天是否有冲突
        //举例，第一天员工2是否工作
        int work1 = form.getDay(day_x).get(employeeId2).get(changeEmployee.getWorkShift1()-1);
        //举例，第二天员工1是否工作
        int work2 = form.getDay(day_y).get(employeeId1).get(changeEmployee.getWorkShift2()-1);
        if(work1==1 || work2==1){
            return R.error("一心不能二用哦！");
        }

        //把employee1在x这天的工作班次停掉
        form.getDay(day_x).get(employeeId1).set(changeEmployee.getWorkShift1()-1,0);

        //让employee2在x这天的工作班次开启
        form.getDay(day_x).get(employeeId2).set(changeEmployee.getWorkShift2()-1,1);

        //把employee2在y这天的工作班次停掉
        form.getDay(day_y).get(employeeId2).set(changeEmployee.getWorkShift2()-1,0);

        //让employee1在y这天的工作班次开启
        form.getDay(day_y).get(employeeId1).set(changeEmployee.getWorkShift1()-1,1);

        //form更新完毕，更新redis，并保证失效时间不流失(不会做，豪猪来想想，我只能保证误差很小)
        String string = JSON.toJSONString(form);
        //时间戳，当前还有多久流失完毕
//        Long time = redisTemplate.opsForValue().getOperations().getExpire("data", TimeUnit.MILLISECONDS);
        //写回redis，以及当前时间戳
//        redisTemplate.opsForValue().set("data",string,time,TimeUnit.MILLISECONDS);
        redisTemplate.opsForValue().set(index,string);
        return R.success("换班成功！");
    }
    


    /**
     * 数据提供
     * @param marketId
     * @param id
     * @return
     */
    public  WorkForm dataPro(String marketId,Long id){
        //用来存放算法中的员工
        HashMap<String, Stuff> stuff_arr = StuffOperator.stuff_arrInit();
        //存放对应店铺的员工集
        List<Employee> employeeList = new ArrayList<>();

        //构造查询条件
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotEmpty(marketId),Employee::getMarketId,marketId);

        //查询
        employeeList = employeeService.list(queryWrapper);


        //将查询出来的员工放入到map集合中
        for(int i = 0;i<employeeList.size();i++){
            Employee employee = employeeList.get(i);
            Stuff temp = new Stuff(employee.getId(),employee.getName(), employee.getPos(), employee.getPhone(), employee.getMail(), employee.getMarketId(), employee.getLoves());
            stuff_arr.put(temp.getName(),temp);
        }

        //查询到对应店铺
        Company company = companyService.getById(id);

        //这里只是把基本的信息传给了从company传给了store,里面一些重要的参数比如preWorkTime
        Store store1 = new Store(company.getName(),company.getAddress(),company.getSize(),stuff_arr);
        //下面这段代码又臭又长，是为了当company中这些参数和store1中不一样时，做个校验
        //后面我们可以修改company的这些属性来达到实现固定和自定义规则
        store1.setPreWorkTime(company.getPreWorkTime());
        store1.setStoreSizeNeedBefore(company.getStoreSizeNeedBefore());
        store1.setPassengerFlowNeed(company.getPassengerFlowNeed());
        store1.setFree_population(company.getFreePopulation());
        store1.setAftWorkTime(company.getAftWorkTime());
        store1.setStoreSizeNeedAfter1(company.getStoreSizeNeedAfter1());
        store1.setStoreSizeNeedAfter2(company.getStoreSizeNeedAfter2());

        long[] employeeNum = new long[stuff_arr.size()]; //存放的是员工id的顺序
        List<Map<String,List<Integer>>> out = new ArrayList<>();


        for(int i = 1;i<=7;i++){
            List<List<Integer>> list = store1.decode(i,employeeNum); //存放的是每个员工一天的工作是否
            Map<String,List<Integer>> res = new HashMap<>();
            for(int j = 0;j<list.size();j++){
                //查名字
                for(Employee e : employeeList){
                    if(e.getId() == employeeNum[j]){
                        res.put(e.getName(),list.get(j));
                        break;
                    }
                }
            }
            out.add(res);
        }
        WorkForm workForm = new WorkForm(out.get(0),out.get(1),out.get(2),out.get(3),out.get(4),out.get(5),out.get(6));
        return workForm;
    }
}
